#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define _free(x) if ( x ){ free(x); x = NULL; }

 #define byte BYTE
 #define word WORD
 #define dwrd LONG


 byte *comp;
 byte *romb;

 struct REGS{
   byte a,
        x,
        y;
 } reg;


 struct RAM{
   dwrd E4,
		E6;
   byte _6535;
   word	_6536;
 } mem;

 dwrd bofs[]={
   0x64765,
   0x649D7,
   0x64B2E,
   0x650DF,
   0x6570D,
   0x00000
 };

 dwrd dofs[]={
   0x647CD,
   0x649FD,
   0x64C2E,
   0x651DF,
   0x65759,
   0x00000
 };

 byte dsze[]={
   0x34,
   0x13,
   0x80,
   0x80,
   0x26,
   0x00
 };

 LONG lpStart,
      lpEnd;

 WORD wpSize,
      cpos,
      rpos,
      ctr ;

 char *dirc = "c:\\romhack\\trans\\dm",
      fil1[260] = "c:\\romhack\\trans\\dm\\dmj.nes",
      fil2[260],
			fil3[260];

 char buf[256];

 FILE *f1,
      *f2,
			*tf;

 char Decomp( word val ),
      Recomp( LONG, LONG, WORD );

 long FileSize( FILE *tf );

int main( int argc, char *argv[] )
{
  clrscr();

  // Try to get some memory to use
  comp = ( byte far *) malloc( 0xFFFF );
  romb = ( byte far *) malloc( 0xFFFF );
  // Test to see if we got memory
  if ( !comp || !romb ){
	printf("Could not allocate enough memory to use..\n"
             "Closing the applixcation...");
	return -1;
  }// END IF

  // Start coding
  printf(" Select process...  \n"
         " [1] - Decompress \n"
         " [2] - Recompress \n"
         " [3] - End Program\n"
        );

  // Switch thru data
  while( !reg.a )
  {
	reg.a = getch();
	switch( reg.a )
	{
	  case '1': // Make the file for recomressing
              sprintf( fil3, "%s\\dmcomp.txt", dirc );
              tf = fopen( fil3, "wt");
              if ( !tf ){
               	fcloseall(); printf("error opening TEXT file...");
            	  return -1;
              }// END IF

		          ctr=-1;
		          while(++ctr < 256){
							  reg.a = Decomp( ctr );
								if ( reg.a ) break;
							}
							reg.a = 1;
              fclose( tf );
							break;
    //---------------------------------
	  case '2':
  		if ( argc > 1 ){
        tf = fopen( argv[1], "rt" );
        if ( !tf ) return -1;
      }
      //
      while( fgets( buf, 256, tf ) )
			{
        if ( !strncmpi( buf, ".comp", 5 ) )
				{
          sscanf( buf, "%s %s %s %lX %lX %X", &fil1, &fil1, &fil2, &lpStart, &lpEnd, &wpSize );
		      Recomp( lpStart, lpEnd, wpSize );
        }
      }
      //
      fclose( tf );
			reg.a = 2; break;
    //-----------------------
	  case '3':
	  case 27 : reg.a = 1; break;
	  default : reg.a = 0; break;
	}
  }// WEND

  // Free up used memory
  _free(comp);
  _free(romb);

  return 0;
}// END OF MAIN



//////////////////////////////////
//                              //
// Decompress the ROM data      //
//                              //
//////////////////////////////////
char Decomp( word val )
{
  byte *tree,
  	   tpos;

  // Test for a valid offset
  if ( !bofs[val] ) return -1;

  // Open the file(s)
  f1 = fopen( fil1,"rb");
  if ( !f1 ){
  	fcloseall(); printf("error opening SOURCE file...");
	  return -1;
  }// END IF

  // Make the file name
  sprintf(fil2,"%s\\cs_%03d.dmp",dirc,val);

  f2 = fopen( fil2,"wb");
  if ( !f2 ){
  	fcloseall(); printf("error opening DESTINATION file...");
	  return -1;
  }// END IF


  // Print it
  gotoxy(1,6); printf("Dumping...%s",fil2);

  ///////////////////////////////////////
  // Start prepping the start values   //
  // Load to the pointer data [offset] //
  ///////////////////////////////////////
  mem.E4 = bofs[val];
  mem.E6 = dofs[val];
  // Try to get memory for the tree
  tree = (byte far *) malloc( mem.E6 - mem.E4 );
  if ( !tree ) return -1;

  // Load up the data for the tree
  fseek(f1,mem.E4,SEEK_SET);
  fread(tree,1,( mem.E6 - mem.E4 ),f1);
  tpos = 0;

  // Get to the Static data
  fseek(f1,mem.E6,SEEK_SET);

  // init start of buffer
  cpos = 0;
  memset(comp,0,0xFFFF);


  ////////////////////////////////
  // Loop through the routine   //
  ////////////////////////////////
  mem._6536 = dsze[val] << 1;
  while ( mem._6536-- > 0 ){
	mem._6535 = tree[tpos++];  // Load up testing BYTE
	reg.x = 0;                 // Set counter to 0

	while( reg.x < 8 ){

	  // Test for a bit set
	  // If so, then it's static data
	  if ( mem._6535 & 0x80 )
		  comp[cpos++] = fgetc(f1);
	  // We have compression
	  else
		comp[cpos++] = 0;

	  // Increment the counter
	  reg.x++;
          mem._6535 <<= 1;
	}// WEND

  }// WEND


  /////////////////////////////////
  // Store the data to the file  //
  /////////////////////////////////
//  printf("%lX",ftell(f1));

  fprintf( tf, ".COMP %s %s %08lX %08lX %04X\n", fil1, fil2, mem.E4, ftell( f1 ), dsze[val] );

  fwrite(comp, 1,cpos, f2);
  fclose( f1 );
  fclose( f2 );
	_free(tree);
  return 0;
}// END OF SUB



//////////////////////////////////
//                              //
// Recompress the ROM data      //
//                              //
//////////////////////////////////
char Recomp( LONG lpStart, LONG lpEnd, WORD wpSize )
{
  byte *tree,
  	   tpos;

  byte data;
  word Maxx,
       Maxp,
       Most;

  // Open the file(s)
  f1 = fopen( fil1, "rb+" );
  f2 = fopen( fil2,"rb");
  if ( !f1 || !f2 )
	{
	  fcloseall();
		printf("error opening WORKING file(s)...");
  	return -1;
  }// END IF

  // Print it
  gotoxy( 1 ,6 );
	printf( "Inserting...%s", fil2 );


  ///////////////////////////////////////
  // Start prepping the start values   //
  // Load to the pointer data [offset] //
  ///////////////////////////////////////
  mem.E4 = lpStart;
  mem.E6 = lpEnd;
  // Try to get memory for the tree
  tree = (BYTE far *) malloc( (wpSize << 1) );
  if ( !tree ) return -1;

  // Load up the data for the tree
  fseek( f1, mem.E4 - (wpSize << 1), SEEK_SET );
  fread( tree, 1, (wpSize << 1), f1 );
  tpos = 0;

  // Get to the Static data
  fseek( f1, mem.E4, SEEK_SET );

  // init start of buffer
  cpos = 0;
  memset( comp, 0, 0xFFFF );


  ////////////////////////////////
  // Loop through the routine   //
  ////////////////////////////////
  mem._6536 = (wpSize << 1);
  while ( mem._6536-- > 0 )
	{
//	  mem._6535 = tree[tpos++];  // Load up testing BYTE
  	reg.x     = 0;                 // Set counter to 0
    mem._6535 = 0;
    //
	  while( reg.x < 8 )
		{ // Loop thru and check the data
      data = fgetc( f2 );
      if ( !data )
			{
        mem._6535 <<= 1;

      }
			else
      {
        mem._6535  <<= 1;
        mem._6535   |= 1;
        comp[cpos++] = data;
      }

/*
  	  // Test for a bit set
	    // If so, then it's static data
	    if ( mem._6535 & 0x80 )
		    comp[cpos++] = fgetc(f1);
  	  // We have compression
  	  else
	    	comp[cpos++] = 0;

*/
  	  // Increment the counter
	    reg.x++;
//      mem._6535 <<= 1;
   	}// WEND

    //
    tree[ tpos++ ] = mem._6535;
  }// WEND


  /////////////////////////////////
  // Store the data to the file  //
  /////////////////////////////////
//  printf("%lX",ftell(f1));
  fseek( f1, mem.E4, SEEK_SET );

  if ( (cpos + mem.E4 + (wpSize << 1)) < mem.E6 )
  {
    fwrite(tree, 1, (wpSize << 1), f1);
    fwrite(comp, 1, cpos, f1);
  }
	else
    printf( "Compressed size is too large" );
  //
  fclose( f1 );
  fclose( f2 );
	_free(tree);

  return 0;
}// END OF SUB



/////////////////////////////////
// Get the length of the file  //
/////////////////////////////////
long FileSize( FILE *tf )
{
 long val;

 // Test file
 if ( !tf ) return -1;

 // Get size
 fseek(tf, 0, SEEK_END);
 val = ftell(tf);
 fseek(tf, 0, SEEK_SET);

 return val;
}// END OF SUB
